using MediatR;
using Microsoft.EntityFrameworkCore;
using SupplierCustomerManagement.Infrastructure;
using SupplierCustomerManagement.Read.API.Applications.Commands.breeding;
using SupplierCustomerManagement.Read.API.Dtos.Breeding;

namespace SupplierCustomerManagement.Read.API.Applications.CommandHandlters.breeding
{
    public class GetEstimatedRateQueryHandler : IRequestHandler<GetEstimatedRateQuery, List<EstimatedRateRowDto>>
    {
        private readonly SupplierDbContext _db;
        private readonly ILogger<GetEstimatedRateQueryHandler> _logger;

        public GetEstimatedRateQueryHandler(SupplierDbContext db, ILogger<GetEstimatedRateQueryHandler> logger)
        {
            _db = db;
            _logger = logger;
        }

        public async Task<List<EstimatedRateRowDto>> Handle(GetEstimatedRateQuery request, CancellationToken cancellationToken)
        {
            // 推荐口径实现：
            // - 周度追踪（week01~week19）：基于妊检阳性 + 配种日期计算孕周，将 D 回溯 19 周按周分箱，计数（以配种事件为单位）。
            // - breedingCount：近19周内发生配种的种母数（EweId 去重）。
            // - estimated：预计产羔数 = 预计分娩窗口 [D, D+30] 内的预计分娩母羊数（按 1 胎占位）。
            // - actual：实际产羔数 = 实际分娩窗口 [D-30, D] 内的 TotalLambs 之和。
            // - lambingRate：actual / estimated。
            // - expectedProduction：预计分娩窗口内的预计分娩母羊数（EweId 去重）。
            // - npd：先置 0（后续按空怀天数口径完善）。

            if (!DateTime.TryParse(request.Date, out var day))
            {
                day = DateTime.Today;
            }

            var windowDays = 30;
            var trackStart = day.AddDays(-7 * 19);

            // 1) 周度追踪：存在阳性妊检的配种记录，按孕周（由 BreedingDate -> D）落入 1..19 进行分箱
            var pregnantBreedingDates = await _db.BreedingRecords
                .AsNoTracking()
                .Where(b => b.BreedingDate <= day && b.BreedingDate >= trackStart)
                .Where(b => _db.PregnancyChecks
                    .Any(pc => pc.BreedingId == b.Id && pc.CheckDate <= day && pc.CheckResult == "怀孕"))
                .Select(b => new { b.Id, b.EweId, b.BreedingDate })
                .ToListAsync(cancellationToken);

            int[] weeks = new int[19];
            foreach (var r in pregnantBreedingDates)
            {
                var diffDays = (day.Date - r.BreedingDate.Date).TotalDays;
                var bin = (int)Math.Floor(diffDays / 7.0); // 0..18 对应 week01..week19
                if (bin >= 0 && bin < 19)
                {
                    weeks[bin] += 1;
                }
            }

            // 2) breedingCount：近19周内发生配种的种母数（EweId 去重）
            var breedingCount = await _db.BreedingRecords
                .AsNoTracking()
                .Where(b => b.BreedingDate >= trackStart && b.BreedingDate <= day)
                .Select(b => b.EweId)
                .Distinct()
                .CountAsync(cancellationToken);

            // 3) estimated/expectedProduction：预计分娩窗口 [D, D+30]
            var estimateStart = day.Date;
            var estimateEnd = day.Date.AddDays(windowDays);

            var expectedBreeding = await _db.BreedingRecords
                .AsNoTracking()
                .Where(b => b.ExpectedLambingDate.HasValue && b.ExpectedLambingDate.Value.Date >= estimateStart && b.ExpectedLambingDate.Value.Date < estimateEnd)
                .Select(b => new { b.EweId })
                .ToListAsync(cancellationToken);

            var expectedProduction = expectedBreeding
                .Select(x => x.EweId)
                .Distinct()
                .Count();

            // estimated：先按 1 胎占位（可改用历史平均胎数）
            var estimated = expectedProduction;

            // 4) actual：实际产羔窗口 [D-30, D]
            var actualStart = day.Date.AddDays(-windowDays);
            var actualEnd = day.Date.AddDays(0);

            var actual = await _db.LambingRecords
                .AsNoTracking()
                .Where(l => l.LambingDate.Date >= actualStart && l.LambingDate.Date < actualEnd)
                .SumAsync(l => (int?)l.TotalLambs, cancellationToken) ?? 0;

            // 5) lambingRate
            var lambingRate = estimated == 0 ? "0%" : string.Format("{0:P0}", (double)actual / estimated);

            var row = new EstimatedRateRowDto
            {
                week = "总计",
                breeding = string.Empty,
                breedingCount = breedingCount,
                week01 = weeks[0],
                week02 = weeks[1],
                week03 = weeks[2],
                week04 = weeks[3],
                week05 = weeks[4],
                week06 = weeks[5],
                week07 = weeks[6],
                week08 = weeks[7],
                week09 = weeks[8],
                week10 = weeks[9],
                week11 = weeks[10],
                week12 = weeks[11],
                week13 = weeks[12],
                week14 = weeks[13],
                week15 = weeks[14],
                week16 = weeks[15],
                week17 = weeks[16],
                week18 = weeks[17],
                week19 = weeks[18],
                estimated = estimated,
                actual = actual,
                lambingRate = lambingRate,
                npd = 0,
                expectedProduction = expectedProduction
            };

            return new List<EstimatedRateRowDto> { row };
        }
    }
}
